struct JacobianDictBlock <: Block
    M
    steady_state_options
    solve_steady_state_options
    impulse_nonlinear_options
    solve_impulse_nonlinear_options
    impulse_linear_options
    jacobian_options
    partial_jacobians_options

    J
    outputs
    inputs
    name
    T

    function JacobianDictBlock(nesteddict; outputs=nothing, inputs=nothing, name=nothing)
        _M = Bijection(Dict())
        _steady_state_options = Dict()
        _solve_steady_state_options = Dict{String, Any}(
            "solver" => "",
            "solver_kwargs" => Dict(),
            "ttol" => 1e-12,
            "ctol" => 1e-9,
            "verbose" => false,
            "constrained_method" => "linear_continuation",
            "constrained_kwargs" => Dict())
        _impulse_nonlinear_options = Dict()
        _solve_impulse_nonlinear_options = Dict(
            "tol" => 1e-8,
            "maxit" => 30,
            "verbose" => true)
        _impulse_linear_options = Dict()
        _jacobian_options = Dict()
        _partial_jacobians_options = Dict()

        _J = JacobianDict(nesteddict; outputs=outputs, inputs=inputs, name=name)

        return new(_M,
                    _steady_state_options,
                    _solve_steady_state_options,
                    _impulse_nonlinear_options,
                    _solve_impulse_nonlinear_options,
                    _impulse_linear_options,
                    _jacobian_options,
                    _partial_jacobians_options,
                    _J,
                    _J.outputs,
                    _J.inputs,
                    _J.name,
                    _J.T)
    end
end

function Base.show(io::IO, obj::JacobianDictBlock)
    println(io, "<JacobianDictBlock outputs=$(obj.outputs), inputs=$(obj.inputs)>")
end

function _impulse_linear(obj::JacobianDictBlock, ss, inputs, outputs, Js)
    J = jacobian(obj, ss, keys(inputs), outputs; T=inputs.T, Js=Js)
    return ImpulseDict(apply(J, inputs))
end

function _jacobian(obj::JacobianDictBlock, ss, inputs, outputs; T)
    if !(inputs ⊆ obj.inputs)
        missing_inputs = setdiff(inputs, obj.inputs)
        error("Asking JacobianDictBlock for $missing_inputs, which are among its inputs $(obj.inputs)")
    end
    if !(outputs ⊆ obj.outputs)
        missing_outputs = setdiff(outputs, obj.outputs)
        error("Asking JacobianDictBlock for $missing_outputs, which are among its outputs $(obj.outputs)")
    end
    return obj[(outputs, inputs)]
end
    
Base.getindex(b::JacobianDictBlock, k) = Base.getindex(b.J, k)
